let CANVAS_WIDTH = 1024                 // canvas 宽
let CANVAS_HEIGHT = 768                 // canvas 高
let RADIUS = 8                          // 小球半径
let MARGIN_TOP = 60                     // 所有数字距离画布上边距
let MARGIN_LEFT = 30                    // 第一个数字距离画布左边距
let TEXT_COLOR = 'rgb(0,102,153)'       // 文本颜色
let ballMaxCount = 300                  // 小球最多产生的数量

// 距离指定时间的倒计时
// let endTime = new Date(2020, 10, 6, 8, 30, 0)       // 倒计时结束的时间，由于小时只显示了两位数，所以倒计时结束时间不超过4天
// let curShowTimeSeconds = 0                          // 现在倒计时有多少秒

// 倒计时几小时
let endHour = 3
let endTime = new Date()
endTime.setTime( endTime.getTime() + 3600*1000*endHour )
let curShowTimeSeconds = 0

// 时钟效果
// let curShowTimeSeconds = 0

let balls = []                          // 掉落的小球
const colors = ["#33B5E5", "#0099CC", "#AA66CC", "#9933CC", "#99CC00", "#669900", "#FFBB33", "#FF8800", "#FF4444", "#CC0000"]   // 掉落的小球的颜色

window.onload = function () {

    initElement()

    let canvas = document.getElementById('canvas')
    let context = canvas.getContext('2d')
    canvas.width = CANVAS_WIDTH
    canvas.height = CANVAS_HEIGHT

    curShowTimeSeconds = getCurrentShowTimeSeconds()

    setInterval(() => {
        render(context)
        update()
    }, 50)

}

/**
 * 初始化各元素（根据屏幕自适应）
 */
function initElement() {

    // canvas 宽高设置成 body 宽高
    CANVAS_WIDTH = document.body.clientWidth
    CANVAS_HEIGHT = document.body.clientHeight

    // 数字左边距及上边距
    MARGIN_LEFT = Math.round(CANVAS_WIDTH / 10)
    MARGIN_TOP = Math.round(CANVAS_HEIGHT / 5)

    // 小球的半径
    RADIUS = Math.round(CANVAS_WIDTH * 4 / 5 / 108) - 1

}

/**
 * 绘制倒计时数字及掉落的小球
 * @param {Object} cxt 绘图上下文对象
 */
function render(cxt) {

    cxt.clearRect(0, 0, cxt.canvas.width, cxt.canvas.height)        // 清除之前的图像，否则每次变化的图像会叠加

    let hours = parseInt(curShowTimeSeconds / 3600)
    let minutes = parseInt((curShowTimeSeconds - hours * 3600) / 60)
    let seconds = curShowTimeSeconds % 60

    // 绘制倒计时数字
    renderDigit(MARGIN_LEFT, MARGIN_TOP, parseInt(hours / 10), cxt)                         // 绘制小时的十位数
    renderDigit(MARGIN_LEFT + 15 * (RADIUS + 1), MARGIN_TOP, parseInt(hours % 10), cxt)     // 绘制小时的个位数
    renderDigit(MARGIN_LEFT + 30 * (RADIUS + 1), MARGIN_TOP, 10, cxt)                       // 绘制冒号
    renderDigit(MARGIN_LEFT + 39 * (RADIUS + 1), MARGIN_TOP, parseInt(minutes / 10), cxt)   // 绘制分钟的十位数
    renderDigit(MARGIN_LEFT + 54 * (RADIUS + 1), MARGIN_TOP, parseInt(minutes % 10), cxt)   // 绘制分钟的个位数
    renderDigit(MARGIN_LEFT + 69 * (RADIUS + 1), MARGIN_TOP, 10, cxt)                       // 绘制冒号
    renderDigit(MARGIN_LEFT + 78 * (RADIUS + 1), MARGIN_TOP, parseInt(seconds / 10), cxt)   // 绘制秒钟的十位数
    renderDigit(MARGIN_LEFT + 93 * (RADIUS + 1), MARGIN_TOP, parseInt(seconds % 10), cxt)   // 绘制秒钟的个位数

    // 绘制掉落的小球
    for (let i = 0; i < balls.length; i++) {
        cxt.fillStyle = balls[i].color

        cxt.beginPath()
        cxt.arc(balls[i].x, balls[i].y, RADIUS, 0, 2 * Math.PI, true)
        cxt.closePath()

        cxt.fill()
    }
}

function update() {

    let nextShowTimeSeconds = getCurrentShowTimeSeconds()

    // 下次要显示的时间
    let nextHours = parseInt(nextShowTimeSeconds / 3600)
    let nextMinutes = parseInt((nextShowTimeSeconds - nextHours * 3600) / 60)
    let nextSeconds = nextShowTimeSeconds % 60

    // 当前显示的时间
    let curHours = parseInt(curShowTimeSeconds / 3600)
    let curMinutes = parseInt((curShowTimeSeconds - curHours * 3600) / 60)
    let curSeconds = curShowTimeSeconds % 60

    if (nextSeconds != curSeconds) {        // 下次要显示的时间与当前显示的时间不同时，要产生变化
        if (parseInt(curHours / 10) != parseInt(nextHours / 10)) {      // 当前小时的十位数不等于下一小时的十位数
            addBalls(MARGIN_LEFT + 0, MARGIN_TOP, parseInt(curHours / 10))
        }
        if (parseInt(curHours % 10) != parseInt(nextHours % 10)) {      // 当前小时的个位数不等于下一小时的个位数
            addBalls(MARGIN_LEFT + 15 * (RADIUS + 1), MARGIN_TOP, parseInt(curHours / 10))
        }

        if (parseInt(curMinutes / 10) != parseInt(nextMinutes / 10)) {  // 当前分钟的十位数不等于下一分钟的十位数
            addBalls(MARGIN_LEFT + 39 * (RADIUS + 1), MARGIN_TOP, parseInt(curMinutes / 10))
        }
        if (parseInt(curMinutes % 10) != parseInt(nextMinutes % 10)) {  // 当前分钟的个位数不等于下一分钟的个位数
            addBalls(MARGIN_LEFT + 54 * (RADIUS + 1), MARGIN_TOP, parseInt(curMinutes % 10))
        }

        if (parseInt(curSeconds / 10) != parseInt(nextSeconds / 10)) {  // 当前秒数的十位数不等于下一秒数的十位数
            addBalls(MARGIN_LEFT + 78 * (RADIUS + 1), MARGIN_TOP, parseInt(curSeconds / 10))
        }
        if (parseInt(curSeconds % 10) != parseInt(nextSeconds % 10)) {  // 当前秒数的个位数不等于下一秒数的个位数
            addBalls(MARGIN_LEFT + 93 * (RADIUS + 1), MARGIN_TOP, parseInt(nextSeconds % 10))
        }

        curShowTimeSeconds = nextShowTimeSeconds        // 下次的时间赋值给当前时间
    }

    updateBalls()

    console.log(balls.length)
}

/**
 * 对所有已经存在的小球的状态进行更新
 */
function updateBalls() {

    for (let i = 0; i < balls.length; i++) {

        balls[i].x += balls[i].vx

        let c = 1.0
        if (balls[i].y + RADIUS + balls[i].vy >= CANVAS_HEIGHT) {
            c = (CANVAS_HEIGHT - (balls[i].y + RADIUS)) / balls[i].vy
            console.log(c)
        }

        balls[i].y += balls[i].vy
        balls[i].vy += c * balls[i].g

        // 碰撞检测：小球碰到底部反弹
        if (balls[i].y >= CANVAS_HEIGHT - RADIUS) {
            balls[i].y = CANVAS_HEIGHT - RADIUS
            balls[i].vy = - Math.abs(balls[i].vy) * 0.75
        }
    }

    // 性能优化操作
    let cnt = 0
    for (let i = 0; i < balls.length; i++) {
        if (balls[i].x + RADIUS > 0 && balls[i].x - RADIUS < CANVAS_WIDTH) balls[cnt++] = balls[i]
    }
    while (balls.length > Math.min(ballMaxCount, cnt)) {     // 将小球数量控制在 cnt 到 ballMaxCount 之间
        balls.pop()
    }
}










/**
 * 绘制某一个具体的数字
 * @param {Number} x 从哪个点开始绘制
 * @param {Number} y 从哪个点开始绘制
 * @param {Number} num 绘制的数字或冒号在digit中的索引
 * @param {Object} cxt 绘图上下文
 */
function renderDigit(x, y, num, cxt) {

    cxt.fillStyle = TEXT_COLOR

    for (let i = 0; i < digit[num].length; i++) {
        for (let j = 0; j < digit[num][i].length; j++) {
            if (digit[num][i][j] == 1) {        // 点阵中当前位置为1，可以绘制
                cxt.beginPath()
                cxt.arc(x + j * 2 * (RADIUS + 1) + (RADIUS + 1), y + i * 2 * (RADIUS + 1) + (RADIUS + 1), RADIUS, 0, 2 * Math.PI)
                cxt.closePath()

                cxt.fill()
            }
        }
    }
}

/**
 * 获取当前倒计时有多少秒
 */
function getCurrentShowTimeSeconds() {
    let curTime = new Date()

    // 倒计时效果
    let ret = endTime.getTime() - curTime.getTime()
    ret = Math.round(ret / 1000)
    return ret >= 0 ? ret : 0

    // 时钟效果
    // let ret = curTime.getHours() * 3600 + curTime.getMinutes() * 60 + curTime.getSeconds()
    // return ret
}

/**
 * 根据num在digit点阵中相应的位置增加小球
 * @param {Number} x 数字位置
 * @param {Number} y 数字位置
 * @param {Number} num 哪个数字
 */
function addBalls(x, y, num) {
    for (let i = 0; i < digit[num].length; i++) {
        for (let j = 0; j < digit[num][i].length; j++) {
            if (digit[num][i][j] == 1) {
                let aBall = {
                    x: x + j * 2 * (RADIUS + 1) + (RADIUS + 1),
                    y: y + i * 2 * (RADIUS + 1) + (RADIUS + 1),
                    g: 1.5 + Math.random(),
                    vx: Math.pow(-1, Math.ceil(Math.random() * 1000)) * 4,
                    vy: -5,
                    color: colors[Math.floor(Math.random() * colors.length)]
                }
                balls.push(aBall)
            }
        }
    }
}